﻿
Imports System.Reflection
Imports std
Imports lock_t = lock(Of locks.monitorlock)

Partial Public Class [property]
    Private Const separator As Char = character.dot
    Private Shared ReadOnly m As map(Of String, invoker(Of [property].ctor_d)) = Nothing
    Private Shared ml As lock_t

    Shared Sub New()
        m = New map(Of String, invoker(Of [property].ctor_d))()
        register(Of int64_property)()
        register(Of cached_int64_property)()
        register(Of string_property)()
        register(Of cached_string_property)()
        register(Of vector_string_property)()
        register(Of cached_vector_string_property)()
        register(Of vector_int64_property)()
        register(Of cached_vector_int64_property)()
        register(Of set_string_property)()
        register(Of cached_set_string_property)()
        register(Of set_int64_property)()
        register(Of cached_set_int64_property)()
    End Sub

    Private Shared Function type_name(Of T As iproperty)() As String
        Return type_name(GetType(T))
    End Function

    Private Shared Function type_name(ByVal t As Type) As String
        assert(Not t Is Nothing)
        Dim f As fieldvalue(Of String) = Nothing
        f = New fieldvalue(Of String)(t, BindingFlags.NonPublic Or BindingFlags.Static, "default_type")
        assert(f.valid())
        Return +f
    End Function

    Public Shared Sub register(Of T As iproperty)()
        Dim tp As Type = Nothing
        tp = GetType(T)
        Dim n As String = Nothing
        n = type_name(tp)
        Dim ctor As invoker(Of ctor_d) = Nothing
        ctor = New invoker(Of ctor_d)(tp, BindingFlags.Public Or BindingFlags.Static, "ctor")
        assert(ctor.valid())
        ml.wait()
        assert(m.find(n) = m.end())
        m(n) = ctor
        ml.release()
    End Sub

    Private Shared Function find_ctor(ByVal type As String, ByRef ctor As invoker(Of ctor_d)) As Boolean
        Dim it As map(Of String, invoker(Of ctor_d)).iterator = Nothing
        ml.wait()
        it = m.find(type)
        If it <> m.end() Then
            ctor = (+it).second
        End If
        ml.release()
        Return Not ctor Is Nothing
    End Function

    'the key of a property in the storage is
    '   id.name.type
    '   such as, for the name of a node with id = 123 and handled by string_property will have a storage key as
    '   123.name.string_proprty
    Public Shared Function create(ByVal key As String, ByRef name As String) As iproperty
        Dim ss As vector(Of String) = Nothing
        strsepar(key, separator, ss)
        If Not ss Is Nothing AndAlso ss.size() = 3 Then
            Dim id As Int64 = 0
            Dim ctor As invoker(Of ctor_d) = Nothing
            If Not convertor.toint64(ss(0), id) Then
                raiseError(errorHandle.errorType.warning, "id ", ss(0), " is not a valid int64")
                Return Nothing
            End If
            name = ss(1)
            Return create(id, name, ss(2))
        Else
            raiseError(errorHandle.errorType.warning, "cannot split key ", key)
            Return Nothing
        End If
    End Function

    Public Shared Function create(ByVal id As Int64,
                                  ByVal name As String,
                                  ByVal type As String) As iproperty
        Dim ctor As invoker(Of ctor_d) = Nothing
        If isemptystring(name) Then
            raiseError(errorHandle.errorType.warning, "name of id ", id, " is an empty string")
            Return Nothing
        End If
        If Not find_ctor(type, ctor) Then
            raiseError(errorHandle.errorType.warning, "cannot find ctor for type ", type)
            Return Nothing
        End If
        Dim p As iproperty = Nothing
        p = (+ctor)(id, name)
        assert(Not p Is Nothing)
        Return p
    End Function

    Public Shared Function create(Of T As iproperty) _
                                 (ByVal id As Int64, ByVal name As String) As T
        Return convertor.cast(Of T)(create(id, name, type_name(Of T)))
    End Function
End Class
